package com.youlai.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.common.constant.SystemConstants;
import com.youlai.system.common.enums.MenuTypeEnum;
import com.youlai.system.common.enums.StatusEnum;
import com.youlai.system.common.model.Option;
import com.youlai.system.converter.HotBrandConverter;
import com.youlai.system.mapper.HotBrandMenuMapper;
import com.youlai.system.model.bo.RouteBO;
 import com.youlai.system.model.entity.HotBrandMenu;
import com.youlai.system.model.form.HotBrandForm;
import com.youlai.system.model.query.MenuQuery;
import com.youlai.system.model.vo.HotBrandVO;
import com.youlai.system.model.vo.RouteVO;
import com.youlai.system.service.HotBrandService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * 菜单业务实现类
 *
 * @author haoxr
 * @since 2020/11/06
 */
@Service
@RequiredArgsConstructor
public class HotBrandServiceImpl extends ServiceImpl<HotBrandMenuMapper, HotBrandMenu> implements HotBrandService {

    private final HotBrandConverter menuConverter;


    /**
     * 菜单列表
     *
     * @param queryParams {@link MenuQuery}
     */
    @Override
    public List<HotBrandVO> listMenus(MenuQuery queryParams) {
        List<HotBrandMenu> menus = this.list(new LambdaQueryWrapper<HotBrandMenu>()
                .like(StrUtil.isNotBlank(queryParams.getKeywords()), HotBrandMenu::getBrandName, queryParams.getKeywords()).orderByAsc(HotBrandMenu::getSort)
        );
        // 获取所有菜单ID
        Set<Integer> menuIds = menus.stream()
                .map(HotBrandMenu::getHotBrandId)
                .collect(Collectors.toSet());

        // 获取所有父级ID
        Set<Integer> parentIds = menus.stream()
                .map(HotBrandMenu::getParentHotBrandId)
                .collect(Collectors.toSet());

        // 获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，注意这里不能拿顶级菜单 O 作为根节点，因为菜单筛选的时候 O 会被过滤掉
        List<Integer> rootIds = parentIds.stream()
                .filter(id -> !menuIds.contains(id))
                .toList();

        // 使用递归函数来构建菜单树
        return rootIds.stream()
                .flatMap(rootId -> buildMenuTree(rootId, menus).stream())
                .collect(Collectors.toList());
    }

    /**
     * 递归生成菜单列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return 菜单列表
     */
    private List<HotBrandVO> buildMenuTree(Integer parentId, List<HotBrandMenu> menuList) {
        return CollectionUtil.emptyIfNull(menuList)
                .stream()
                .filter(menu -> menu.getParentHotBrandId().equals(parentId))
                .map(entity -> {
                    HotBrandVO brandVO = menuConverter.entity2Vo(entity);
                    List<HotBrandVO> children = buildMenuTree(entity.getHotBrandId(), menuList);
                    brandVO.setChildren(children);
                    return brandVO;
                }).toList();
    }

    /**
     * 菜单下拉数据
     */
    @Override
    public List<Option> listMenuOptions() {
        List<HotBrandMenu> menuList = this.list(new LambdaQueryWrapper<HotBrandMenu>()
                .orderByAsc(HotBrandMenu::getHotBrandId));
        return buildMenuOptions(0, menuList);
    }

    /**
     * 递归生成菜单下拉层级列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return 菜单下拉列表
     */
    private List<Option> buildMenuOptions(Integer parentId, List<HotBrandMenu> menuList) {
        List<Option> menuOptions = new ArrayList<>();

        for (HotBrandMenu menu : menuList) {
            if (menu.getParentHotBrandId().equals(parentId)) {
                Option option = new Option(menu.getHotBrandId(), menu.getBrandName());
                List<Option> subMenuOptions = buildMenuOptions(menu.getHotBrandId(), menuList);
                if (!subMenuOptions.isEmpty()) {
                    option.setChildren(subMenuOptions);
                }
                menuOptions.add(option);
            }
        }

        return menuOptions;
    }

    /**
     * 获取路由列表
     */
    @Override
    @Cacheable(cacheNames = "menu", key = "'routes'")
    public List<RouteVO> listRoutes() {
        List<RouteBO> menuList = this.baseMapper.listHotRoutes();
        return buildRoutes(SystemConstants.ROOT_NODE_ID, menuList);
    }

    /**
     * 递归生成菜单路由层级列表
     *
     * @param parentId 父级ID
     * @param menuList 菜单列表
     * @return 路由层级列表
     */
    private List<RouteVO> buildRoutes(Long parentId, List<RouteBO> menuList) {
        List<RouteVO> routeList = new ArrayList<>();

        for (RouteBO menu : menuList) {
            if (menu.getParentId().equals(parentId)) {
                RouteVO routeVO = toRouteVo(menu);
                List<RouteVO> children = buildRoutes(menu.getId(), menuList);
                if (!children.isEmpty()) {
                    routeVO.setChildren(children);
                }
                routeList.add(routeVO);
            }
        }

        return routeList;
    }

    /**
     * 根据RouteBO创建RouteVO
     */
    private RouteVO toRouteVo(RouteBO routeBO) {
        RouteVO routeVO = new RouteVO();
        String routeName = StringUtils.capitalize(StrUtil.toCamelCase(routeBO.getPath(), '-'));  // 路由 name 需要驼峰，首字母大写
        routeVO.setName(routeName); // 根据name路由跳转 this.$router.push({name:xxx})
        routeVO.setPath(routeBO.getPath()); // 根据path路由跳转 this.$router.push({path:xxx})
        routeVO.setRedirect(routeBO.getRedirect());
        routeVO.setComponent(routeBO.getComponent());

        RouteVO.Meta meta = new RouteVO.Meta();
        meta.setTitle(routeBO.getName());
        meta.setIcon(routeBO.getIcon());
        meta.setRoles(routeBO.getRoles());
        meta.setHidden(StatusEnum.DISABLE.getValue().equals(routeBO.getVisible()));
        // 【菜单】是否开启页面缓存
        if (MenuTypeEnum.MENU.equals(routeBO.getType())
                && ObjectUtil.equals(routeBO.getKeepAlive(), 1)) {
            meta.setKeepAlive(true);
        }
        // 【目录】只有一个子路由是否始终显示
        if (MenuTypeEnum.CATALOG.equals(routeBO.getType())
                && ObjectUtil.equals(routeBO.getAlwaysShow(), 1)) {
            meta.setAlwaysShow(true);
        }

        routeVO.setMeta(meta);
        return routeVO;
    }

    /**
     * 新增/修改菜单
     */
    @Override
    @CacheEvict(cacheNames = "menu", key = "'routes'")
    public boolean saveMenu(HotBrandForm hotBrandForm) {
        HotBrandMenu entity = menuConverter.form2Entity(hotBrandForm);
        return this.saveOrUpdate(entity);
    }



    /**
     * 修改菜单显示状态
     *
     * @param menuId  菜单ID
     * @param visible 是否显示(1->显示；2->隐藏)
     * @return
     */
    @Override
    @CacheEvict(cacheNames = "menu", key = "'routes'")
    public boolean updateMenuVisible(Long menuId, Integer visible) {
        return this.update(new LambdaUpdateWrapper<HotBrandMenu>()
                .eq(HotBrandMenu::getHotBrandId, menuId)
        );
    }

    /**
     * 获取角色权限(Code)集合
     *
     * @param roles 角色Code集合
     * @return 权限集合
     */
    @Override
    public Set<String> listRolePerms(Set<String> roles) {
        return this.baseMapper.listRolePerms(roles);
    }

    /**
     * 获取菜单表单数据
     *
     * @param id 菜单ID
     * @return 菜单表单数据
     */
    @Override
    public HotBrandForm getMenuForm(Long id) {
        HotBrandMenu entity = this.getById(id);
        return menuConverter.entity2Form(entity);
    }

    /**
     * 删除菜单
     *
     * @param id 菜单ID
     * @return 是否删除成功
     */
    @Override
    @CacheEvict(cacheNames = "menu", key = "'routes'")
    public boolean deleteMenu(Long id) {
        MenuQuery queryParams=new MenuQuery();

        List<HotBrandMenu> menus = this.list(new LambdaQueryWrapper<HotBrandMenu>()
                .like(StrUtil.isNotBlank(queryParams.getKeywords()), HotBrandMenu::getBrandName, queryParams.getKeywords()).orderByDesc(HotBrandMenu::getSort)
        );
        AtomicBoolean isDj= new AtomicBoolean(false);
       menus.forEach(item->{
           if(item.getHotBrandId().toString().equals(id.toString()) && item.getParentHotBrandId()==0){
               isDj.set(true);
           }
       });
        if(CollectionUtils.isNotEmpty(menus) && isDj.get()){
            // 获取所有菜单ID
            Set<Integer> menuIds = menus.stream()
                    .map(HotBrandMenu::getHotBrandId)
                    .collect(Collectors.toSet());

            // 获取所有父级ID
            Set<Integer> parentIds = menus.stream()
                    .map(HotBrandMenu::getParentHotBrandId)
                    .collect(Collectors.toSet());

            // 获取根节点ID（递归的起点），即父节点ID中不包含在部门ID中的节点，注意这里不能拿顶级菜单 O 作为根节点，因为菜单筛选的时候 O 会被过滤掉
            List<Integer> rootIds = parentIds.stream()
                    .filter(ids -> !menuIds.contains(ids))
                    .toList();

            // 使用递归函数来构建菜单树
            List<HotBrandVO> brandVOList= rootIds.stream()
                    .flatMap(rootId -> buildMenuTree(rootId, menus).stream())
                    .collect(Collectors.toList());

            brandVOList.forEach(item->{
                if(item.getHotBrandId().toString().equals(id.toString())) {
                    this.remove(new LambdaQueryWrapper<HotBrandMenu>()
                            .eq(HotBrandMenu::getHotBrandId, item.getHotBrandId()));
                    item.getChildren().forEach(subItem -> {
                        this.remove(new LambdaQueryWrapper<HotBrandMenu>()
                                .eq(HotBrandMenu::getHotBrandId, subItem.getHotBrandId()));
                        this.remove(new LambdaQueryWrapper<HotBrandMenu>()
                                .eq(HotBrandMenu::getParentHotBrandId, subItem.getHotBrandId()));
                    });
                }
            });
          return  true;

        }else {

            this.remove(new LambdaQueryWrapper<HotBrandMenu>()
                    .eq(HotBrandMenu::getParentHotBrandId, id));

            return this.remove(new LambdaQueryWrapper<HotBrandMenu>()
                    .eq(HotBrandMenu::getHotBrandId, id));
        }
    }

    @Override
    public List<HotBrandVO> brandList() {
        return this.baseMapper.selectHotBrandList();
    }


}
